die( "This file is part of MediaWiki, it is not a valid entry point" );
}
-use Liuggio\StatsdClient\Sender\SocketSender;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\ProcOpenError;
use MediaWiki\Session\SessionManager;
/**
* @todo document
+ * @todo Move logic to MediaWiki.php
*/
function wfLogProfilingData() {
global $wgDebugLogGroups, $wgDebugRawPage;
$profiler->setContext( $context );
$profiler->logData();
- $config = $context->getConfig();
- $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
- if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
- try {
- $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
- $statsdHost = $statsdServer[0];
- $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
- $statsdSender = new SocketSender( $statsdHost, $statsdPort );
- $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
- $statsdClient->setSamplingRates( $config->get( 'StatsdSamplingRates' ) );
- $statsdClient->send( $stats->getData() );
- } catch ( Exception $ex ) {
- MWExceptionHandler::logException( $ex );
- }
- }
+ // Send out any buffered statsd metrics as needed
+ MediaWiki::emitBufferedStatsdData(
+ MediaWikiServices::getInstance()->getStatsdDataFactory(),
+ $context->getConfig()
+ );
- # Profiling must actually be enabled...
+ // Profiling must actually be enabled...
if ( $profiler instanceof ProfilerStub ) {
return;
}
use Wikimedia\Rdbms\ChronologyProtector;
use Wikimedia\Rdbms\LBFactory;
use Wikimedia\Rdbms\DBConnectionError;
+use Liuggio\StatsdClient\Sender\SocketSender;
/**
* The MediaWiki class is the helper class for the index.php entry point.
wfDebug( "Request ended normally\n" );
}
+ /**
+ * Send out any buffered statsd data according to sampling rules
+ *
+ * @param IBufferingStatsdDataFactory $stats
+ * @param Config $config
+ * @throws ConfigException
+ * @since 1.31
+ */
+ public static function emitBufferedStatsdData(
+ IBufferingStatsdDataFactory $stats, Config $config
+ ) {
+ if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
+ try {
+ $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
+ $statsdHost = $statsdServer[0];
+ $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
+ $statsdSender = new SocketSender( $statsdHost, $statsdPort );
+ $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
+ $statsdClient->setSamplingRates( $config->get( 'StatsdSamplingRates' ) );
+ $statsdClient->send( $stats->getData() );
+
+ $stats->clearData(); // empty buffer for the next round
+ } catch ( Exception $ex ) {
+ MWExceptionHandler::logException( $ex );
+ }
+ }
+ }
+
/**
* Potentially open a socket and sent an HTTP request back to the server
* to run a specified number of jobs. This registers a callback to cleanup
return $this->buffer;
}
- /**
- * Check whether this data factory has any data.
- * @return bool
- */
public function hasData() {
return !empty( $this->buffer );
}
- /**
- * Return data from the factory.
- * @return StatsdData[]
- */
public function getData() {
return $this->buffer;
}
- /**
- * Set collection enable status.
- * @param bool $enabled Will collection be enabled?
- * @return void
- */
+ public function clearData() {
+ $this->buffer = [];
+ }
+
+ public function getDataCount() {
+ return count( $this->buffer );
+ }
+
public function setEnabled( $enabled ) {
$this->enabled = $enabled;
}
*/
interface IBufferingStatsdDataFactory extends StatsdDataFactoryInterface {
/**
- * Check whether this data factory has any data.
+ * Check whether this data factory has any buffered data.
* @return bool
*/
public function hasData();
/**
- * Return data from the factory.
+ * Return the buffered data from the factory.
* @return StatsdData[]
*/
public function getData();
+ /**
+ * Clear all buffered data from the factory
+ * @since 1.31
+ */
+ public function clearData();
+
+ /**
+ * Return the number of buffered statsd data entries
+ * @return int
+ * @since 1.31
+ */
+ public function getDataCount();
+
/**
* Set collection enable status.
* @param bool $enabled Will collection be enabled?
* @return void
*/
public function setEnabled( $enabled );
-
}
return $data;
}
- /**
- * Check whether this data factory has any data.
- * @return bool
- */
public function hasData() {
return false;
}
- /**
- * Return data from the factory.
- * @return StatsdData[]
- */
public function getData() {
return [];
}
- /**
- * Set collection enable status.
- * @param bool $enabled Will collection be enabled?
- * @return void
- */
+ public function clearData() {
+ // Nothing to do, always empty
+ }
+
+ public function getDataCount() {
+ return 0;
+ }
+
public function setEnabled( $enabled ) {
// Nothing to do, null factory is always disabled.
}
* @param mixed $channel Unique identifier for the channel. See function outputChanneled.
*/
protected function output( $out, $channel = null ) {
+ // Try to periodically flush buffered metrics to avoid OOMs
+ $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
+ if ( $stats->getDataCount() > 1000 ) {
+ MediaWiki::emitBufferedStatsdData( $stats, $this->getConfig() );
+ }
if ( $this->mQuiet ) {
return;
}
$lbFactory->setAgentName(
mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
);
- self::setLBFactoryTriggers( $lbFactory );
+ self::setLBFactoryTriggers( $lbFactory, $this->getConfig() );
}
/**
* @param LBFactory $LBFactory
+ * @param Config $config
* @since 1.28
*/
- public static function setLBFactoryTriggers( LBFactory $LBFactory ) {
+ public static function setLBFactoryTriggers( LBFactory $LBFactory, Config $config ) {
+ $services = MediaWikiServices::getInstance();
+ $stats = $services->getStatsdDataFactory();
// Hook into period lag checks which often happen in long-running scripts
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory = $services->getDBLoadBalancerFactory();
$lbFactory->setWaitForReplicationListener(
__METHOD__,
- function () {
- global $wgCommandLineMode;
+ function () use ( $stats, $config ) {
// Check config in case of JobRunner and unit tests
- if ( $wgCommandLineMode ) {
+ if ( $config->get( 'CommandLineMode' ) ) {
DeferredUpdates::tryOpportunisticExecute( 'run' );
}
+ // Try to periodically flush buffered metrics to avoid OOMs
+ MediaWiki::emitBufferedStatsdData( $stats, $config );
}
);
// Check for other windows to run them. A script may read or do a few writes
// to the master but mostly be writing to something else, like a file store.
$lbFactory->getMainLB()->setTransactionListener(
__METHOD__,
- function ( $trigger ) {
- global $wgCommandLineMode;
+ function ( $trigger ) use ( $stats, $config ) {
// Check config in case of JobRunner and unit tests
- if ( $wgCommandLineMode && $trigger === IDatabase::TRIGGER_COMMIT ) {
+ if ( $config->get( 'CommandLineMode' ) && $trigger === IDatabase::TRIGGER_COMMIT ) {
DeferredUpdates::tryOpportunisticExecute( 'run' );
}
+ // Try to periodically flush buffered metrics to avoid OOMs
+ MediaWiki::emitBufferedStatsdData( $stats, $config );
}
);
}
// XXX: reset maintenance triggers
// Hook into period lag checks which often happen in long-running scripts
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- Maintenance::setLBFactoryTriggers( $lbFactory );
+ $services = MediaWikiServices::getInstance();
+ $lbFactory = $services->getDBLoadBalancerFactory();
+ Maintenance::setLBFactoryTriggers( $lbFactory, $services->getMainConfig() );
ob_start( 'MediaWikiTestCase::wfResetOutputBuffersBarrier' );
}